﻿/*
 * KLF Headless Browser
 * Written by Kris Oye <kristianoye@gmail.com>
 * Copyright (C) 2011-2012.  All rights reserved.
 */
namespace KLF.Lib.Browser
{
    #region Using Statements

    using Jint;
    using System;
    using Jint.Native;
    using System.Reflection;
    using KLF.Lib.Browser.DOM;
    using KLF.Lib.Browser.DOM.HTML;
    using KLF.Lib.Browser.DOM.Events;
    using KLF.Lib.Browser.JavaScriptHelpers;

    #endregion

    internal class JavascriptContext : RequestContext, IDisposable
    {
        #region Constructors

        /// <summary>
        /// Construct the JavascriptContext
        /// </summary>
        /// <param name="request">The request being executed.</param>
        /// <param name="document">The parent document.</param>
        internal JavascriptContext(RequestContext request, HTMLDocument document)
            : base(request)
        {
            ActiveDocument = document;
            Script = request.BuildScriptContext(ActiveDocument);
            ParentContext = request;

            document.Context = this;
        }

        #endregion

        #region Properties

        /// <summary>
        /// The active document that contains the script being executed.
        /// </summary>
        internal HTMLDocument ActiveDocument { get; set; }

        #endregion

        #region Methods

        /// <summary>
        /// Execute a block of script extracted from the document.
        /// </summary>
        /// <param name="scriptBlock"></param>
        public void ExecuteScript(HTMLScriptElement scriptBlock)
        {
            ActiveDocument.WriteContext = scriptBlock;
            ActiveDocument.currentScript = scriptBlock;

            try
            {
                var result = Script.Run(scriptBlock.Code);
            }
            catch (Exception ex)
            {
                bool handled = Browser.ScriptError(ActiveDocument, scriptBlock, ex);
                Browser.ScriptPostExecute(ActiveDocument, scriptBlock, false);

                //  If the error was not caught/handled elsewhere, throw it up
                if (!handled)
                {
                    throw ex;
                }
            }

            ActiveDocument.WriteContext = null;
            ActiveDocument.currentScript = null;
        }

        #endregion

        #region IDisposable Members

        /// <summary>
        /// If this JavascriptContext was executing for a frame embedded in a
        /// document (child/parent relation) or as a JavaScript popup window
        /// (opener), then those relationships must be cleared out of the 
        /// master's JavaScript context before releasing.
        /// </summary>
        public new void Dispose()
        {
            ActiveDocument.Context = ParentContext;
        }

        #endregion
    }
}
